package intermouse;


import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

/**
 * A pályát kezelő osztály, nyilvántartja az adott kört, a pályán lévő
 * szereplőket és felelős a körönkénti léptetésért.
 * 
 * @author Demény Fruzsina Gyöngyi
 * @version 1.0
 * @since 2013-03-23
 */
public class Level {

	/************* Attributes *****************/

	/**
	 * A köröket számolja, megadja a jelenlegi kör sorszámát.
	 */
	private int currentRound;
	/**
	 * A hangyákat tároló lista.
	 */
	private List<Ant> antList;
	/**
	 * A hangyára káros entitásokat tároló lista (hangyaleső, hangyaszsün,
	 * méreg).
	 */
	private List<Malicious> maliciousList;
	/**
	 * A hangyaboly referenciáját tárolja.
	 */
	private AntHill antHill;
	/**
	 * A mezők referenciáját tároló lista.
	 */
	private List<Field> fields;
	
	private int levelWidth = 60, levelHeight = 40;
	
	static Level instance= null;
	
	/************* Constructors *****************/

	/**
	 * A Level osztály default konstruktora.
	 */
	private Level() {
		currentRound = 0;
		antList = new ArrayList<Ant>();
		maliciousList = new ArrayList<Malicious>();
		fields = new ArrayList<Field>();
		antHill = new AntHill();
		
		
		for(int i = 0; i < levelHeight; i++) //i a magasság (sorok száma)
		{ 
			for(int j = 0; j < levelWidth; j++)
			{		
					Field field=new Field();
					field.setCoords(i, j);
					for (int k = 0; k < 6; k++) //kitöltjük az adjacent fields-eket null-al egyelőre
						field.getAdjacentFields().add(null);
					fields.add(field); //és betesszük a fieldek közé lol
					
			}	
		}
			//  | -			    j:
			//	| :i   		- ----> +
			//	V +			
			
			//Itt töltjük ki az adjacent fields-et
			for(int i = 0; i < levelHeight; i++)  
			{
				for(int j = 0; j < levelWidth; j++) //oszlopok száma
				{
					if(i%2==0) //ha a sor páros (0. az első sor)
				{

					try { //levelHeight * Y KOORDINÁTA + X KOORDINÁTA
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(0, fields.get(levelWidth * (i-1) + (j+1)));
					} catch (IndexOutOfBoundsException e) { //gyors, és igénytelen fix (túlindexelsz, csak nem történik semmi)
					}

					try {
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(1, fields.get(levelWidth * (i) + (j + 1)));
					} catch (IndexOutOfBoundsException e) {
					}

					try {
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(2, fields.get(levelWidth * (i + 1) + (j + 1)));
					} catch (IndexOutOfBoundsException e) {
					}

					try {
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(3, fields.get(levelWidth * (i + 1) + (j)));
					} catch (IndexOutOfBoundsException e) {
					}

					try { fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(4,fields.get(levelWidth * (i) + (j - 1)));
					} catch (IndexOutOfBoundsException e) {
					}

					try {fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(5, fields.get(levelWidth * (i - 1) + (j)));
					} catch (IndexOutOfBoundsException e) {
					}
				}
					else
 {
					try {
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(0, fields.get(levelWidth * (i - 1) + (j)));
					} catch (IndexOutOfBoundsException e) {
					}

					try {
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(1,	fields.get(levelWidth * (i)	+ (j+1)));
					} catch (IndexOutOfBoundsException e) {
					}

					try {
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(2, fields.get(levelWidth * (i + 1) + (j)));
					} catch (IndexOutOfBoundsException e) {
					}

					try {
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(3, fields.get(levelWidth * (i + 1) + (j - 1)));
					} catch (IndexOutOfBoundsException e) {
					}

					try {
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(4,	fields.get(levelWidth * (i)	+ (j - 1)));
					} catch (IndexOutOfBoundsException e) {
					}

					try {
						fields.get(levelWidth * (i) + (j)).getAdjacentFields()
								.set(5, fields.get(levelWidth * (i - 1) + (j - 1)));
					} catch (IndexOutOfBoundsException e) {
					}
				}
			}
			}
//			edgek hozzáadása
			for(int i=0; i<60; i++){
				fields.get(i).addFieldObject(new Edge());
			}
			
			for(int i=0; i<60; i++){
				fields.get(39*60+i).addFieldObject(new Edge());
			}
			
			for(int i=1; i<39; i++){
				fields.get(60*i).addFieldObject(new Edge());
			}
			
			for(int i=1; i<39; i++){
				fields.get(60*i+59).addFieldObject(new Edge());
			}
			
	
	}

	/************* Getters *****************/

	/**
	 * @return Visszaadja a currentRound változó értékét, ami integer típusú.
	 */
	public int getCurrentRound() {
		Logger.printToConsole(">> Level.getCurrentRound() : int");
		Logger.printToConsole("<< return" + currentRound);
		return currentRound;
	}
	
	public static Level getInstance(){
		if(instance==null)
			instance=new Level();
		return instance;
	}

	/************* Setters *****************/


	/**
	 * @param i
	 *            A currentRound változó új értéke.
	 */
	public void setCurrentRound(int i) {
		Logger.printToConsole(">> Level.setCurrentRound(i:int) : void");
		this.currentRound = i;
		Logger.printToConsole("<< return");
	}

	/**
	 * @param antHill
	 *            A hangyaboly referenciáját állítja be.
	 */
	public void setAntHill(AntHill antHill) {
		Logger.printToConsole(">> ::Level.setAntHill(antHill:AntHill) : void");
		this.antHill = antHill;
		Logger.printToConsole("<< return");
	}

	/************* Methods *****************/
	/**
	 * A pálya inicializálását végző függvény.
	 */
	public void init() {
		Logger.printToConsole(">> Main::Level.init() : void");
	
		Random r = new Random();
		for(int i=0; i<10; i++){
			Water water=new Water();
			water.setField(fields.get((4+r.nextInt(32))*60+4+r.nextInt(52)));
			water.spreadWater(3);
		}
		
		for(int i=0; i<100; i++){
			int x,y;
			do{
				x=1+r.nextInt(38);
				y=1+r.nextInt(58);
			}while(Level.getInstance().getFields().get(x*60+y).getObj().isEmpty()==false);
			new Stone().setField(Level.getInstance().getFields().get(x*60+y));
		}
		

		for(int i=0; i<50; i++){
			int x,y;
			do{
				x=1+r.nextInt(38);
				y=1+r.nextInt(58);
			}while(Level.getInstance().getFields().get(x*60+y).getObj().isEmpty()==false);
			for(int h=r.nextInt(10);h>0;h--){
				new Food().setField(Level.getInstance().getFields().get(x*60+y));
			}
		}
		
		for(int i=0; i<40; i++){
			int x,y;
			do{
				x=1+r.nextInt(38);
				y=1+r.nextInt(58);
			}while(Level.getInstance().getFields().get(x*60+y).getObj().isEmpty()==false);
			AntLion antLion=new AntLion();
			antLion.setField(Level.getInstance().getFields().get(x*60+y));
			Level.getInstance().addToMaliciousList(antLion);
		}
		
		for(int i=0; i<1; i++){
			int x,y;
			do{
				x=1+r.nextInt(38);
				y=1+r.nextInt(58);
			}while(Level.getInstance().getFields().get(x*60+y).getObj().isEmpty()==false);
			this.antHill.setField(Level.getInstance().getFields().get(x*60+y));
		}
		
		for(int i=0; i<1; i++){
			int x,y;
			do{
				x=1+r.nextInt(38);
				y=1+r.nextInt(58);
			}while(Level.getInstance().getFields().get(x*60+y).getObj().isEmpty()==false);
			AntEater antEater=new AntEater();
			antEater.setField(Level.getInstance().getFields().get(x*60+y));
			Level.getInstance().addToMaliciousList(antEater);
			
		}
		
		
		
//		//Fieldek létrehozása
//		for(int i = 0; i < levelHeight; i++)
//		{
//			for(int j = 0; j < levelWidth; j++)
//			{
//
//				if (i == 20 && j == 37) {Stone a = new Stone(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 25 && j == 30) {Stone a = new Stone(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 31 && j == 20) {Stone a = new Stone(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 9 && j == 2) {Stone a = new Stone(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 1 && j == 14) {Stone a = new Stone(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				
//				if (i == 1 && j == 1) {AntEater a = new AntEater(); a.setField(fields.get(levelWidth * (i) + (j))); this.maliciousList.add(a); }
//				
//				if (i == 5 && j == 5) {
//					this.antHill.setField(fields.get(levelWidth * (i) + (j)));
//				}
//				
//				if (i == 20 && j == 20) {Water w = new Water();  w.setField(fields.get(levelWidth * (i) + (j))); 	w.spreadWater(8);}
//
//				if (i == 12 && j == 14) {AntLion a = new AntLion(); a.spawn(fields.get(levelWidth * (i) + (j))); this.maliciousList.add(a);}
//				if (i == 32 && j == 16)  {AntLion a = new AntLion(); a.spawn(fields.get(levelWidth * (i) + (j))); this.maliciousList.add(a);}
//				if (i == 11 && j == 34)  {AntLion a = new AntLion(); a.spawn(fields.get(levelWidth * (i) + (j))); this.maliciousList.add(a);}
//				if (i == 34 && j == 11)  {AntLion a = new AntLion(); a.spawn(fields.get(levelWidth * (i) + (j))); this.maliciousList.add(a);}
//				if (i == 22 && j == 30)  {AntLion a = new AntLion(); a.spawn(fields.get(levelWidth * (i) + (j))); this.maliciousList.add(a);}
//				
//				if (i == 17 && j == 34) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 17 && j == 34) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 17 && j == 34) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 17 && j == 34) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 17 && j == 34) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 32 && j == 11) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 32 && j == 11) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 32 && j == 11) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 32 && j == 11) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 35 && j == 25) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 37 && j == 23) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 34 && j == 23) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 32 && j == 23) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 37 && j == 10) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 27 && j == 10) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 37 && j == 10) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				if (i == 37 && j == 10) {Food a = new Food(); a.setField(fields.get(levelWidth * (i) + (j))); }
//				
//			}
//		}

		
		Logger.printToConsole("<< return");
	}

	/**
	 * A körök lebonyolítását végzi, meghívja a szereplők beginRound()
	 * függvényeit.
	 * 
	 */
	public void makeStep() {
		Logger.printToConsole(">> Level.makeStep() : void");
		if (antHill != null)
			if (antHill.field != null)

				if (this.getCurrentRound() % 3 == 0) 

					antList.add(antHill.createAnt());
		
		
		
		Iterator<Ant> it = antList.iterator();
		while (it.hasNext()) {
			Ant a = it.next();
			if (a.getDead())
				it.remove();
		}
		for (Field f : fields) {
			f.beginRound();
		}
		for (Ant a : antList) {
			a.beginRound();
		}
		for (Malicious m : maliciousList) {
			if (m.respawnable && (this.getCurrentRound()+1) % 60 == 0)
			{
				m.spawn(m.getField());
			}
			m.beginRound();
		}
		currentRound++;
		
		int foodcount = 0;
		for (Field f : fields) {
			foodcount += f.getFoodCount();
		}
		
		if (foodcount == 0)
		{
			//GAME OVER
			GameState.getInstance().addToPlayerScore(GameState.getInstance().getAntKillerSpraysLeft() * 6);
			GameState.getInstance().addToPlayerScore(GameState.getInstance().getAntDeodorantSpraysLeft() * 3);
						
			Main.gameOver();
		}
		
		Logger.printToConsole("<< return");
	}

	/**
	 * A maliciousList listához hozzáad egy új elemet, amely Poison típusú.
	 * 
	 * @param f
	 *            A mező referenciáját adja meg, ahol a méreg elhelyezkedik.
	 */
	public void addPoison(Field f) {
		Logger.printToConsole(">> Level.addPosion(f:Field) : void");
		Poison p = new Poison();
		p.spawn(f);
		maliciousList.add(p);
		Logger.printToConsole("<< return");
	}
	
	public void addToMaliciousList(Malicious m)
	{
		if (m == null) return;
		maliciousList.add(m);
	}

	/**
	 * Az antList listához hozzáadja a paraméterként kapott hangyát.
	 * 
	 * @param ant
	 *            A hangya referenciája, amit a listához kell adni.
	 */
	public void addAnt(Ant ant) {
		Logger.printToConsole(">> Level.addAnt(ant:Ant) : void");
		antList.add(ant);
		Logger.printToConsole("<< return");
	}
	public List<Field> getFields(){
		Logger.printToConsole(">> Level.getFields() : List<Field>");
		Logger.printToConsole("<< return");
		List<Field> ret = new ArrayList<Field>();
		for(int i = 0; i < fields.size(); i++)
			ret.add(fields.get(i));
		return ret;
	}
	
	static public void reset(){
		instance= new Level();
	}
	/*
	public Field getFieldFromFields(int index) {
		return fields.get(index);
	}*/
	// ha a getFields shallowcopyt ad akkor ez nem kell
}
